/*
utf-8
------------------------------------------------
闹钟程序
------------------------------------------------
由刘丙旭出品
遵循署名-非商业性使用-相同方式共享 4.0 国际协议 (CC BY-NC-SA 4.0)
详情访问https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh
------------------------------------------------
*/

module clock_alarmclock(
input [3:0] HH,HL,MH,ML,	//计时模块的时钟输入，与设置的时间作比较
input clk,
input RESET,		//重置闹钟
input MODE,			//1时计时，0时设置时间
input SETBIT,		//设置位置
input SET,				//每按下一次加一
input en,					//1使能

output [3:0] ac_HH_out,ac_HL_out,ac_MH_out,ac_ML_out,
output [3:0] ac_on_off_l,ac_on_off_r,
output reg [5:0] dp = 5'b010100,

output buzzer

);
	
	
	//reg [2:0] state;		//需要5个状态
	
	reg [3:0] ac_HH,ac_HL,ac_MH,ac_ML;  //闹钟设置的时间
	reg [4:0] BIT = 5'b00001;				//前四位调整，最后一位开关
	reg on_off;											//闹钟开关:1开;0关
	reg [2:0] alarm_state;
	
	reg MODE_tem1,MODE_tem2;
	wire MODE_pluse;
	always @(posedge clk)
	begin
		MODE_tem1 <= MODE;
		MODE_tem2 <= MODE_tem1;
	end
	assign MODE_pluse = ~MODE_tem1 & MODE_tem2;
	
	reg RESET_tem1,RESET_tem2;
	wire RESET_pluse;
	always @(posedge clk)
	begin
		RESET_tem1 <= RESET;
		RESET_tem2 <= RESET_tem1;
	end
	assign RESET_pluse = ~RESET_tem1 & RESET_tem2;
	
	reg SETBIT_tem1,SETBIT_tem2;
	wire SETBIT_pluse;
	always @(posedge clk)
	begin
		SETBIT_tem1 <= SETBIT;
		SETBIT_tem2 <= SETBIT_tem1;
	end
	assign SETBIT_pluse = ~SETBIT_tem1 & SETBIT_tem2;
	
	reg SET_tem1,SET_tem2;
	wire SET_pluse;
	always @(posedge clk)
	begin
		SET_tem1 <= SET;
		SET_tem2 <= SET_tem1;
	end
	assign SET_pluse = ~SET_tem1 & SET_tem2;
	
	always @(negedge SETBIT)
	begin
	if (BIT[0])
		BIT <= 5'b10000;
	else
		BIT <= BIT >> 1;
	end
	
	always @(posedge clk)
	if (~MODE) begin
		case(BIT)
			5'b10000:begin
				if (SET_pluse)
					begin  
						if(ac_HH == 4'd2)
							ac_HH <= 4'd0;
						else 
							ac_HH <= ac_HH + 1;
					end    
			end        
			5'b01000:begin
				if (SET_pluse) 
					begin
						if(ac_HH == 4'd2)
							begin
								if(ac_HL >= 4'd3)
									ac_HL <= 4'd0;
								else
									ac_HL <= ac_HL + 1;
							end
						else
							begin
								if(ac_HL >= 4'd9)
									ac_HL <= 4'd0;
								else
									ac_HL <= ac_HL + 1;
							end
					end
			end
			5'b00100:begin
				if (SET_pluse)
					begin
						if(ac_MH == 4'd5)
							ac_MH <= 4'd0;
						else
							ac_MH <= ac_MH + 1;
					end
			end
			5'b00010:begin
				if (SET_pluse)
					begin
						if(ac_ML == 4'd9)
							ac_ML <= 4'd0;
						else
							ac_ML <= ac_ML + 1;
					end
			end
			5'b00001:begin
				if (SET_pluse)
					on_off <= ~on_off; //1开；0关
					
			end
					
			//default:
		endcase
	end
	
	reg [29:0] buzzer_delay;
	reg buzzer_stop = 1'b1;
	reg buzzer_0 = 1'b1;
	
	always @(posedge clk)
	if(MODE & en)
	case(alarm_state)
		3'd0:begin
			buzzer_0 <= 1'b1;
			if(HH == ac_HH & HL == ac_HL & MH == ac_MH & ML == ac_ML)
				if(on_off)
					begin alarm_state <= 3'd1; end
		end
		3'd1:begin
			if(buzzer_delay == 249_999_999)
				begin 
					buzzer_stop <= 1'b1; 
					buzzer_delay <= 0;
					buzzer_0 <= 1'b1;
					alarm_state <= 3'd2;
				end
			else
				begin 
					buzzer_stop <= 1'b0;
					buzzer_delay <= buzzer_delay + 1;
					buzzer_0 <= clk_1kHz;
				end
		end
		3'd2:begin
			if(HH == ac_HH & HL == ac_HL & MH == ac_MH & ML == ac_ML)
				alarm_state <= 3'd2;
			else
				alarm_state <= 3'd0;
		end
		//3'd3:
		//3'd4:
		//3'd5:
		//3'd6:
		//3'd7:
	endcase
	
	//整点报时
	//检测HL[0]
	
	reg nowtime_tem1,nowtime_tem2;
	reg nowtime_pluse;
	always @(posedge clk)
	begin
		nowtime_tem1 <= HL[0];
		nowtime_tem2 <= nowtime_tem1;
		
		case({nowtime_tem1,nowtime_tem2})
			2'd0:nowtime_pluse <= 1'b0;
			2'd1:nowtime_pluse <= 1'b1;
			2'd2:nowtime_pluse <= 1'b1;
			2'd3:nowtime_pluse <= 1'b0;
		endcase
	end
	
	parameter delay_short 	= 5_000_000;
	parameter delay_long  	= 20_000_000;
	parameter delay_interval= 5_000_000;
	reg [3:0] nowtime_state;
	reg [2:0] nowtime_count;
	reg [29:0] nowtime_delay;
	reg buzzer_1 = 1'b1;
	
	always @(posedge clk)
	if(buzzer_stop & en)
	case(nowtime_state)
		4'd0:begin
			if(nowtime_pluse == 1'b1)
				begin nowtime_state <= 3'd1;  end
		end
		4'd1:begin
			if(nowtime_delay == delay_short)
				begin nowtime_delay <= 0; nowtime_state <= 4'd2; end
			else
				begin nowtime_delay <= nowtime_delay + 1; buzzer_1 <= 1'b0; end
		end
		4'd2:begin
			if(nowtime_delay == delay_interval)
				begin nowtime_delay <= 0; nowtime_state <= 4'd3; end
			else
				begin nowtime_delay <= nowtime_delay + 1; buzzer_1 <= 1'b1; end
		end
		4'd3:begin
			if(nowtime_delay == delay_short)
				begin nowtime_delay <= 0; nowtime_state <= 4'd4; end
			else
				begin nowtime_delay <= nowtime_delay + 1; buzzer_1 <= 1'b0; end
		end
		4'd4:begin
			if(nowtime_delay == delay_interval)
				begin nowtime_delay <= 0; nowtime_state <= 4'd5; end
			else
				begin nowtime_delay <= nowtime_delay + 1; buzzer_1 <= 1'b1; end
		end
		4'd5:begin
			if(nowtime_delay == delay_short)
				begin nowtime_delay <= 0; nowtime_state <= 4'd6; end
			else
				begin nowtime_delay <= nowtime_delay + 1; buzzer_1 <= 1'b0; end
		end
		4'd6:begin
			if(nowtime_delay == delay_interval)
				begin nowtime_delay <= 0; nowtime_state <= 4'd7; end
			else
				begin nowtime_delay <= nowtime_delay + 1; buzzer_1 <= 1'b1; end
		end
		4'd7:begin
			if(nowtime_delay == delay_short)
				begin nowtime_delay <= 0; nowtime_state <= 4'd8; end
			else
				begin nowtime_delay <= nowtime_delay + 1; buzzer_1 <= 1'b0; end
		end
		4'd8:begin
			if(nowtime_delay == delay_interval)
				begin nowtime_delay <= 0; nowtime_state <= 4'd9; end
			else
				begin nowtime_delay <= nowtime_delay + 1; buzzer_1 <= 1'b1; end
		end
		4'd9:begin
			if(nowtime_delay == delay_long)
				begin nowtime_delay <= 0; nowtime_state <= 4'd10; end
			else
				begin nowtime_delay <= nowtime_delay + 1; buzzer_1 <= 1'b0; end
		end
		4'd10:begin
			if(nowtime_delay == delay_long)
				begin nowtime_delay <= 0; nowtime_state <= 4'd11; end
			else
				begin nowtime_delay <= nowtime_delay + 1; buzzer_1 <= 1'b1; end
		end
		4'd11:begin
			buzzer_1 <= 1'b1;
			if(nowtime_count == 3'd3)
				begin nowtime_count <= 3'd0; nowtime_state <= 4'd0; end
			else
				begin nowtime_count <= nowtime_count + 1; nowtime_state <= 4'd1; end
		end
	endcase
	
	
	
	
	
	
	
	
	assign buzzer = buzzer_0 & buzzer_1;
	
	assign ac_HH_out = (~BIT[4] | clk_1Hz | ~SET)?ac_HH:4'b1111;
	assign ac_HL_out = (~BIT[3] | clk_1Hz | ~SET)?ac_HL:4'b1111;
	assign ac_MH_out = (~BIT[2] | clk_1Hz | ~SET)?ac_MH:4'b1111;
	assign ac_ML_out = (~BIT[1] | clk_1Hz | ~SET)?ac_ML:4'b1111;
	assign ac_on_off_l = (~BIT[0] | clk_1Hz | ~SET)?4'b1100:4'b1111;
	
	wire [3:0] r_tem;
	assign r_tem = on_off?4'b1010:4'b1011;
	assign ac_on_off_r = (~BIT[0] | clk_1Hz | ~SET)?(r_tem):4'b1111;
	
		
	clk_50MHz_1kHz clk_50MHz_1kHz
	(
	.clk_50MHz		(clk),
	.clk_1kHz			(clk_1kHz)
	);
	
	clk_1k_1Hz clk_1k_1Hz
	(
	.clk_1kHz			(clk_1kHz),
	.clk_1Hz			(clk_1Hz)
	);
	
endmodule